/**
 * File: FastqValidationParser.java
 * Created by: mhaimel
 * Created on: 12 Aug 2009
 * CVS:  $Id: FastaValidationParser.java,v 1.2 2009/10/09 15:15:48 mhaimel Exp $
 */
package uk.ac.ebi.curtain.util.file;

import java.io.IOException;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import uk.ac.ebi.curtain.utils.file.EntryMapper;
import uk.ac.ebi.curtain.utils.file.EntryMapperBean;
import uk.ac.ebi.curtain.utils.file.FileInfo;
import uk.ac.ebi.curtain.utils.file.impl.AbstractParser;
import uk.ac.ebi.curtain.utils.io.impl.BufferedRaf;

/**
 * @author mhaimel
 *
 */
public class FastaValidationParser extends AbstractParser {
	
	private Log log = LogFactory.getLog(this.getClass());

	public void parseNEntry(int nCnt, BufferedRaf in, FileInfo info,EntryMapper mapper) throws IOException {
		int iCnt = 0;
		String id = null;
		String header = null;
		StringBuilder seq = new StringBuilder();
		String line = null;
		long nextPos = in.getFilePointer();
		long prevPos = nextPos;
		long currEntryPos = nextPos;
		while((nCnt < 0 || nCnt > iCnt) && (line = in.readLine2()) != null){
			prevPos = nextPos;
			nextPos = in.getFilePointer();
			if(StringUtils.isNotBlank(line) && line.charAt(0) == '>'){
				if(addValid(info,currEntryPos,mapper, id, header, seq)){
					++iCnt;
				}
				currEntryPos = prevPos;
				// reset values
				id = null;
				header=null;
				seq.delete(0, seq.length());
				
				// parse
				line = line.substring(1);
				int wsIdx = line.indexOf(' '); // stop at first white space 
				if(wsIdx > 0){
					id = line.substring(0,wsIdx);
					header = line.substring(wsIdx).trim();					
				} else {
					header = StringUtils.EMPTY;
					id = line;
				}
				if(skipId(info, id, currEntryPos)){
					skipSequence(in);
				}
			} else {
				seq.append(line);
			}
			nextPos = in.getFilePointer();
		}
		addValid(info,currEntryPos,mapper, id, header, seq);
	}

	private static final char ENTRY_START = '>';
	protected void skipSequence(BufferedRaf in) throws IOException {
		boolean eos = false;
		while (!eos) {
			switch (in.read()) {
			case -1:
				eos=true;
				break;
			case '\n':
				if(isNextChar(ENTRY_START,in)){
					eos=true;
				}
				break;
			case '\r':
				long cur = in.getFilePointer();
				if ((in.read()) != '\n') {
					in.seek(cur);
				}
				if(isNextChar(ENTRY_START,in)){
					eos=true;
				}
				break;
			default:
				break;
			}
		}
	}

	private boolean isNextChar(char expChar, BufferedRaf in) throws IOException {
		long cur = in.getFilePointer();
		int nChar = in.read();
		in.seek(cur);
		return nChar == expChar;
	}

	protected boolean skipId(FileInfo info, String id, long filePos) {
		return false;
	}

	protected boolean addValid(FileInfo info,long pos, EntryMapper mapper, String id, String header,StringBuilder seq) {
		if(StringUtils.isNotBlank(id)
				&& null != header
				&& seq.length() > 0){
			mapper.mapEntry(buildEntryBean(info, pos, id, header, seq));
			return true;
		} else {
			return false;
		}
	}

	protected EntryMapperBean buildEntryBean(FileInfo info, long pos, String id,String header, StringBuilder seq) {
		return new EntryMapperBean(pos,info,new String(id), new String(header), seq.toString());
	}
	
	private Log getLog(){
		return log;
	}
}
